package top.nana7mi.headshot.util;

import net.minecraft.entity.EntityLivingBase;
import net.minecraft.entity.monster.EntityPolarBear;
import net.minecraft.util.math.AxisAlignedBB;
import net.minecraft.util.math.MathHelper;
import net.minecraft.util.math.RayTraceResult;
import net.minecraft.util.math.Vec3d;

public class HeadShotHandler {
    private static final AxisAlignedBB zero = new AxisAlignedBB(0.0D, 0.0D, 0.0D, 0.0D, 0.0D, 0.0D);

    private static final AxisAlignedBB slimeCore = new AxisAlignedBB(0.4D, 0.4D, 0.4D, 0.6D, 0.6D, 0.6D);

    private static final AxisAlignedBB shulkerCore = new AxisAlignedBB(0.4D, 0.1D, 0.4D, 0.6D, 0.4D, 0.6D);

    private static final AxisAlignedBB humanoidHead = new AxisAlignedBB(0.1D, 0.8D, 0.1D, 0.9D, 1.0D, 0.9D);

    private static final AxisAlignedBB huskHead = new AxisAlignedBB(0.1D, 0.8D, 0.1D, 0.9D, 1.1D, 0.9D);

    private static final AxisAlignedBB spiderHead = new AxisAlignedBB(0.6D, 0.5D, 0.3D, 1.2D, 1.2D, 0.7D);

    private static final AxisAlignedBB chickenHead = new AxisAlignedBB(0.9D, 0.8D, 0.3D, 1.4D, 1.4D, 0.7D);

    private static final AxisAlignedBB cowHead = new AxisAlignedBB(0.9D, 0.7D, 0.2D, 1.4D, 1.2D, 0.8D);

    private static final AxisAlignedBB donkeyHead = new AxisAlignedBB(0.7D, 0.7D, 0.2D, 1.0D, 1.0D, 0.8D);

    private static final AxisAlignedBB guardianEye = new AxisAlignedBB(0.8D, 0.4D, 0.4D, 1.0D, 0.6D, 0.6D);

    private static final AxisAlignedBB ghastEyes = new AxisAlignedBB(0.8D, 0.6D, 0.2D, 1.0D, 0.7D, 0.8D);

    private static final AxisAlignedBB polarBearHead = new AxisAlignedBB(1.0D, 0.6D, 0.2D, 1.5D, 1.0D, 0.8D);

    public static RayTraceResult traceHeadShot(EntityLivingBase entity, Vec3d impactStart, Vec3d impactEnd) {
        return getHeadBox(entity).calculateIntercept(impactStart, impactEnd);
    }

    public static AxisAlignedBB getHeadBox(EntityLivingBase entity) {
        AxisAlignedBB box = zero;
        AxisAlignedBB collisionBoundingBox = entity.getEntityBoundingBox();
        if (entity instanceof net.minecraft.entity.monster.EntitySlime) {
            box = shrinkBoxTo(collisionBoundingBox, slimeCore);
        } else if (entity instanceof net.minecraft.entity.monster.EntityShulker) {
            box = shrinkBoxTo(collisionBoundingBox, shulkerCore);
        } else {
            if (entity instanceof net.minecraft.entity.passive.EntityBat || entity instanceof net.minecraft.entity.monster.EntityEndermite || entity instanceof net.minecraft.entity.passive.EntityOcelot || entity instanceof net.minecraft.entity.passive.EntityParrot || entity instanceof net.minecraft.entity.monster.EntitySilverfish || entity instanceof net.minecraft.entity.passive.EntitySquid)
                return zero;
            if (entity instanceof net.minecraft.entity.monster.EntitySpider) {
                AxisAlignedBB headBoxRotated = rotateAroundY(spiderHead, entity.renderYawOffset);
                box = shrinkBoxTo(collisionBoundingBox, headBoxRotated);
            } else if (entity instanceof net.minecraft.entity.passive.EntityChicken || entity instanceof net.minecraft.entity.passive.EntityRabbit) {
                AxisAlignedBB headBoxRotated = rotateAroundY(chickenHead, entity.renderYawOffset);
                box = shrinkBoxTo(collisionBoundingBox, headBoxRotated);
            } else if (entity instanceof net.minecraft.entity.passive.EntityCow || entity instanceof net.minecraft.entity.passive.EntityPig || entity instanceof net.minecraft.entity.passive.EntitySheep) {
                AxisAlignedBB headBoxRotated = rotateAroundY(cowHead, entity.renderYawOffset);
                box = shrinkBoxTo(collisionBoundingBox, headBoxRotated);
            } else if (entity instanceof net.minecraft.entity.passive.EntityDonkey || entity instanceof net.minecraft.entity.passive.EntityMule || entity instanceof net.minecraft.entity.passive.EntityLlama || entity instanceof net.minecraft.entity.passive.AbstractHorse) {
                AxisAlignedBB headBoxRotated = rotateAroundY(donkeyHead, entity.renderYawOffset);
                box = shrinkBoxTo(collisionBoundingBox, headBoxRotated);
            } else if (entity instanceof net.minecraft.entity.monster.EntityGuardian) {
                AxisAlignedBB headBoxRotated = rotateAroundY(guardianEye, entity.renderYawOffset);
                box = shrinkBoxTo(collisionBoundingBox, headBoxRotated);
            } else if (entity instanceof net.minecraft.entity.monster.EntityGhast) {
                AxisAlignedBB headBoxRotated = rotateAroundY(ghastEyes, entity.renderYawOffset);
                box = shrinkBoxTo(collisionBoundingBox, headBoxRotated);
            } else if (entity instanceof EntityPolarBear) {
                AxisAlignedBB headBoxRotated = rotateAroundY(polarBearHead, entity.renderYawOffset);
                box = shrinkBoxTo(collisionBoundingBox, headBoxRotated);
                if (((EntityPolarBear)entity).swingProgress > 0.2F)
                    box = box.offset(0.0D, ((EntityPolarBear)entity).swingProgress, 0.0D);
            } else if (entity instanceof net.minecraft.entity.passive.EntityWolf) {
                AxisAlignedBB headBoxRotated = rotateAroundY(polarBearHead, entity.renderYawOffset);
                box = shrinkBoxTo(collisionBoundingBox, headBoxRotated);
            } else if (entity instanceof net.minecraft.entity.monster.EntityHusk) {
                box = shrinkBoxTo(collisionBoundingBox, huskHead);
            } else {
                box = shrinkBoxTo(collisionBoundingBox, humanoidHead);
            }
        }
        return box;
    }

    private static AxisAlignedBB rotateAroundY(AxisAlignedBB headBox, float yaw) {
        float cos = MathHelper.cos(-yaw * 0.017453292F);
        float sin = MathHelper.	sin(-yaw * 0.017453292F);
        float dminX = (float)(headBox.minX - 0.5D);
        float dmaxX = (float)(headBox.maxX - 0.5D);
        float dminZ = (float)(headBox.minZ - 0.5D);
        float dmaxZ = (float)(headBox.maxZ - 0.5D);
        float x00 = 0.5F + sin * dminX + cos * dminZ;
        float z00 = 0.5F + cos * dminX + sin * dminZ;
        float x11 = 0.5F + sin * dmaxX + cos * dmaxZ;
        float z11 = 0.5F + cos * dmaxX + sin * dmaxZ;
        float x10 = 0.5F + sin * dmaxX + cos * dminZ;
        float z10 = 0.5F + cos * dmaxX + sin * dminZ;
        float x01 = 0.5F + sin * dminX + cos * dmaxZ;
        float z01 = 0.5F + cos * dminX + sin * dmaxZ;
        return new AxisAlignedBB(
                min(x00, x10, x01, x11), headBox.minY,

                min(z00, z10, z01, z11),
                max(x00, x10, x01, x11), headBox.maxY,

                max(z00, z10, z01, z11));
    }

    private static float min(float v1, float v2, float v3, float v4) {
        float v = v1;
        v = (v2 < v) ? v2 : v;
        v = (v3 < v) ? v3 : v;
        v = (v4 < v) ? v4 : v;
        return v;
    }

    private static float max(float v1, float v2, float v3, float v4) {
        float v = v1;
        v = (v2 > v) ? v2 : v;
        v = (v3 > v) ? v3 : v;
        v = (v4 > v) ? v4 : v;
        return v;
    }

    private static AxisAlignedBB shrinkBoxTo(AxisAlignedBB original, AxisAlignedBB shrinkTo) {
        double sizeX = original.maxX - original.minX;
        double sizeY = original.maxY - original.minY;
        double sizeZ = original.maxZ - original.minZ;
        return new AxisAlignedBB(original.minX + shrinkTo.minX * sizeX, original.minY + shrinkTo.minY * sizeY, original.minZ + shrinkTo.minZ * sizeZ, original.minX + shrinkTo.maxX * sizeX, original.minY + shrinkTo.maxY * sizeY, original.minZ + shrinkTo.maxZ * sizeZ);
    }
}
